<?php
declare(strict_types=1);

namespace WebApp\lib\co\client;

use Generator;
use WebApp\lib\co\core\SystemCall;

/**
 * Class HttpClient
 * @package WebApp\lib\co\client
 */
class HttpClient
{
    private $request_line = "";
    private $request_header = "";
    private $request_info = "";

    private $url_info = null;
    private $header = [];
    private $body = "";

//    private $protocol = 'HTTP/1.1';

    private static $http = null;
    const SEPARATOR = "\r\n";

    /**
     * Http constructor.
     */
    private function __construct()
    {
    }

    /**
     * @return HttpClient
     */
    public static function getInstance(): HttpClient
    {
        if (self::$http === null) {
            self::$http = new self();
        }
        return self::$http;
    }

    /**
     * @param $url
     * @return $this
     */
    public function init($url)
    {
        $this->parseUrl($url);
        $this->header['Host'] = $this->url_info['host'];
        return $this;
    }

    /**
     * @param array $header
     * @return Generator
     */
    public function get($header = []): Generator
    {
        $this->header = array_merge($this->header, $header);
        return $this->request('GET');
    }

    /**
     * @param array $header
     * @param array $body
     * @return Generator
     */
    public function post($header = [], $body = []): Generator
    {
        $this->header = array_merge($this->header, $header);
        if (!empty($body)) {
            $this->body = http_build_query($body);
            $this->header['Content-Type'] = 'application/x-www-form-urlencoded';
            $this->header['Content-Length'] = strlen($this->body);
        }
        return $this->request('POST');
    }

    /**
     * @param $method
     * @return bool
     */
    private function request($method)
    {
        $header = "";
        $this->request_line = $method . ' ' . $this->url_info['path'] . '?' . $this->url_info['query'];
        foreach ($this->header as $key => $value) {
            $header .= $header == "" ? $key . ':' . $value : self::SEPARATOR . $key . ':' . $value;
        }
        $this->request_header = $header . self::SEPARATOR . self::SEPARATOR;
        $this->request_info = $this->request_line . self::SEPARATOR . $this->request_header;
        if ($this->body != "") {
            $this->request_info .= $this->body;
        }
        $port = isset($this->url_info['port']) ? isset($this->url_info['port']) : 80;
        $fp = fsockopen($this->url_info['host'], $port, $err_no, $err_str);

        if (!$fp) {
            echo $err_no . '(' . $err_str . ')';
            return false;
        }
        fwrite($fp, $this->request_info);
        $ret = (yield SystemCall::await($fp));
        return $ret;
    }

    /**
     * @param $url
     */
    private function parseUrl($url)
    {
        $this->url_info = parse_url($url);
    }
}
